/**
* Copyrights 2011 Michal Saman, m.saman@designplus.cz.
* This source code is release under the Apache License 2.0.
* http://www.apache.org/licenses/LICENSE-2.0
*
* @file	 pcontext.h
* @brief Process context structures and handling (IA-32 architecture dependent)
*/

#ifndef PCONTEXT_H
#define PCONTEXT_H

#include <env.h>
#include <stdint.h>
#include <mem/vmu_pde.h>

/**
 * Stores context of process.
 */
typedef struct pcontext {
	uint32_t	pc;					/*<< instruction pointer. Holds the program counter, the current instruction address */
	uint32_t	eax;				/*<< accumulator */
	uint32_t	ebx;				/*<< base index (ex: arrays) */
	uint32_t	ecx;				/*<< counter */
	uint32_t	edx;				/*<< data/general */
	uint32_t	eflags;				/*<< FLAGS register contains flags such as carry flag, overflow flag and zero flag */
	uint32_t	esp;				/*<< stack pointer for top address of the stack */
	uint32_t	ebp;				/*<< stack base pointer for holding the address of the current stack frame */
	uint32_t	esi;				/*<< source index" for string operations */
	uint32_t	edi;				/*<< "destination index" for string operations */
	struct page_directory*		page_dir;			/*<< pointer to process's page directory */
} pcontext_t;

/**
 * Saves machine registers and flags.
 */
#define pcontext_save_from_stack(p) 								\
__asm__ volatile ("movl 28(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.eax));			\
__asm__ volatile ("movl 24(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.ecx));			\
__asm__ volatile ("movl 20(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.edx));			\
__asm__ volatile ("movl 16(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.ebx));			\
__asm__ volatile ("movl 12(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.esp));			\
__asm__ volatile ("movl 8(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.ebp));			\
__asm__ volatile ("movl 4(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.esi));			\
__asm__ volatile ("movl 0(%esp), %esi");							\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.edi));			\
__asm__ volatile ("pushf");											\
__asm__ volatile ("pop %esi");										\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.eflags));		\
__asm__ volatile ("mov %cr3, %esi");								\
__asm__ volatile ("mov %%esi, %0" : "=r"(p->pcontext.page_dir));

#define pcontex_save_pc(p)											\
__asm__ volatile ("push %eax");										\
__asm__ volatile ("call 1f");										\
__asm__ volatile ("jmp 2f");										\
__asm__ volatile ("1: pop %edx");									\
__asm__ volatile ("mov %%edx, %0" : "=m"(p->pcontext.pc));			\
__asm__ volatile ("pop %eax");										\
__asm__ volatile ("2:");

#define pcontex_save_pc_from_stack(p)												\
__asm__ volatile ("movl 32(%esp), %edx");											\
__asm__ volatile ("movl %%edx, %[pc]" : [pc]"=m"(p->pcontext.pc));

#define jump_to_pc(p)	\
__asm__ volatile ("jmp *%0" : : "m"(p->pcontext.pc));


/**
 * Restore machine registers and flags.
 */
#define pcontext_restore(p) 									\
__asm__ volatile ("mov %0, %%edx" : : "m"(p->pcontext.eflags));	\
__asm__ volatile ("push %edx");									\
__asm__ volatile ("popf");										\
__asm__ volatile ("mov %0, %%eax" : : "m"(p->pcontext.eax));	\
__asm__ volatile ("mov %0, %%ebx" : : "m"(p->pcontext.ecx));	\
__asm__ volatile ("mov %0, %%ecx" : : "m"(p->pcontext.edx));	\
__asm__ volatile ("mov %0, %%edx" : : "m"(p->pcontext.ebx));	\
__asm__ volatile ("mov %0, %%esp" : : "m"(p->pcontext.esp));	\
__asm__ volatile ("mov %0, %%ebp" : : "m"(p->pcontext.ebp));

#endif
